/**
 * 
 */
package com.letoo.dragon.common.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.DeleteObjectsResult;
import com.aliyun.oss.model.GenericRequest;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;

/**
 * OSS云存储操作工具类 云账号AccessKey有所有API访问权限，建议遵循阿里云安全最佳实践，创建并使用RAM子账号进行API访问或日常运维，请登录 https://ram.console.aliyun.com 创建
 * 
 * @author dengjie
 *
 */
public class OssUtils {

    private static final Logger LOG = LoggerFactory.getLogger(OssUtils.class);

    /**
     * 简单上传文件
     * 
     * @param endpoint
     *            OSS endpoint
     * @param accessKeyId
     *            OSS accessKeyId
     * @param accessKeySecret
     *            OSS accessKeySecret
     * @param bucketName
     *            OSS bucketName
     * @param fileName
     *            文件名。也是API中的key
     * @param file
     *            文件对象
     * @param fileType
     *            文件类型。
     * @return
     */
    public static boolean uploadFile(String endpoint, String accessKeyId, String accessKeySecret, String bucketName,
            String fileName, File file) {
        // 文件名.命名规则是：图片使用业务类型常量+4位随机数+时间戳
        return putObject(endpoint, accessKeyId, accessKeySecret, bucketName, file, fileName);
    }

    /**
     * 简单上传文件进行文件内容的更新。更新文件:只更新内容，不更新文件名和文件地址。 (因为地址没变，可能存在浏览器原数据缓存，不能及时加载新数据，例如图片更新，请注意)
     * 
     * @param endpoint
     *            OSS endpoint
     * @param accessKeyId
     *            OSS accessKeyId
     * @param accessKeySecret
     *            OSS accessKeySecret
     * @param bucketName
     *            OSS bucketName
     * @param fileName
     *            文件名。也是API中的key
     * @param file
     *            文件对象
     * @param fileType
     *            文件类型。
     * @return 是否更新内容成功
     */
    public static boolean updateFile(String endpoint, String accessKeyId, String accessKeySecret, String bucketName,
            String fileName, File file) {
        return putObject(endpoint, accessKeyId, accessKeySecret, bucketName, file, fileName);
    }

    /**
     * 替换文件:删除原文件并上传新文件，文件名和地址同时替换 解决原数据缓存问题，只要更新了地址，就能重新加载数据)
     * 
     * @param endpoint
     *            OSS endpoint
     * @param accessKeyId
     *            OSS accessKeyId
     * @param accessKeySecret
     *            OSS accessKeySecret
     * @param bucketName
     *            OSS bucketName
     * @param oldFileName
     *            旧文件名。也是API中的key
     * @param newFileName
     *            新文件名。也是API中的key
     * @param file
     *            文件对象
     * @param fileType
     *            文件类型。
     * @return 是否更新内容成功
     */
    public static boolean replaceFile(String endpoint, String accessKeyId, String accessKeySecret, String bucketName,
            String oldFileName, String newFileName, File file) {
        // 先删除原文件
        boolean flag = deleteFile(endpoint, accessKeyId, accessKeySecret, bucketName, oldFileName);
        if (!flag) {
            return false;
        }
        return uploadFile(endpoint, accessKeyId, accessKeySecret, bucketName, newFileName, file);
    }

    /**
     * 单文件删除
     * 
     * @param endpoint
     *            OSS endpoint
     * @param accessKeyId
     *            OSS accessKeyId
     * @param accessKeySecret
     *            OSS accessKeySecret
     * @param bucketName
     *            OSS bucketName
     * @param fileName
     *            文件名。也是API中的key
     * @return boolean 是否删除成功
     */
    public static boolean deleteFile(String endpoint, String accessKeyId, String accessKeySecret, String bucketName,
            String fileName) {
        // 校验输入参数
        if (StringUtils.isBlank(endpoint) || StringUtils.isBlank(accessKeyId) || StringUtils.isBlank(accessKeySecret)
                || StringUtils.isBlank(bucketName) || StringUtils.isBlank(fileName)) {
            LOG.error(String.format(
                    "OssUtils deleteFile method params is blank.the endpoint is:%s;the accessKeyId is:%s;the accessKeySecret is:%s;the bucketName is:%s;the fileName is:%s;",
                    endpoint, accessKeyId, accessKeySecret, bucketName, fileName));
            return false;
        }
        OSSClient ossClient = null;
        try {
            ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
            GenericRequest request = new DeleteObjectsRequest(bucketName).withKey(fileName);
            ossClient.deleteObject(request);
        } catch (Exception oe) {
            LOG.error("OssUtils putObject method is Exception", oe);
            return false;
        } finally {
            ossClient.shutdown();
        }
        return true;
    }

    /**
     * 批量文件删除(较快)：适用于相同endPoint和BucketName
     * 
     * @param endpoint
     *            OSS endpoint
     * @param accessKeyId
     *            OSS accessKeyId
     * @param accessKeySecret
     *            OSS accessKeySecret
     * @param bucketName
     *            OSS bucketName
     * @param fileNames
     *            文件名集合。也是API中的key集合
     * @return int 成功删除的个数
     */
    public static int batchDeleteFile(String endpoint, String accessKeyId, String accessKeySecret, String bucketName,
            List<String> fileNames) {
        // 校验输入参数
        if (StringUtils.isBlank(endpoint) || StringUtils.isBlank(accessKeyId) || StringUtils.isBlank(accessKeySecret)
                || StringUtils.isBlank(bucketName)) {
            LOG.error(String.format(
                    "OssUtils batchDeleteFile method params is blank.the endpoint is:%s;the accessKeyId is:%s;the accessKeySecret is:%s;the bucketName is:%s;the fileName is:%s;",
                    endpoint, accessKeyId, accessKeySecret, bucketName));
            return 0;
        }
        int deleteCount = 0; // 成功删除的个数
        OSSClient ossClient = null;
        try {
            ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
            DeleteObjectsRequest request = new DeleteObjectsRequest(bucketName).withKeys(fileNames);
            DeleteObjectsResult result = ossClient.deleteObjects(request);
            deleteCount = result.getDeletedObjects().size();
        } catch (OSSException oe) {
            LOG.error("OssUtils putObject method is OSSException", oe);
            return 0;
        } catch (ClientException ce) {
            LOG.error("OssUtils putObject method is ClientException", ce);
            return 0;
        } finally {
            ossClient.shutdown();
        }
        return deleteCount;

    }

    /**
     * 
     * @MethodName: putObject
     * @Description: 上传文件
     * @param file
     * @param fileType
     * @param fileName
     * @return String
     */
    private static boolean putObject(String endpoint, String accessKeyId, String accessKeySecret, String bucketName,
            File file, String fileName) {
        // 校验输入参数
        if (StringUtils.isBlank(endpoint) || StringUtils.isBlank(accessKeyId) || StringUtils.isBlank(accessKeySecret)
                || StringUtils.isBlank(bucketName) || StringUtils.isBlank(fileName)) {
            LOG.error(String.format(
                    "OssUtils putObject method params is blank.the endpoint is:%s;the accessKeyId is:%s;the accessKeySecret is:%s;the bucketName is:%s;the fileName is:%s;",
                    endpoint, accessKeyId, accessKeySecret, bucketName, fileName));
            return false;
        }
        OSSClient ossClient = null;
        PutObjectResult result = null;
        try {
            ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
            InputStream input = new FileInputStream(file);
            ObjectMetadata meta = new ObjectMetadata(); // 创建上传Object的Metadata
            meta.setCacheControl("no-cache"); // 被下载时网页的缓存行为
            PutObjectRequest request = new PutObjectRequest(bucketName, fileName, input, meta); // 创建上传请求
            result = ossClient.putObject(request);
        } catch (OSSException oe) {
            LOG.error("OssUtils putObject method is OSSException", oe);
            return false;
        } catch (ClientException ce) {
            LOG.error("OssUtils putObject method is ClientException", ce);
            return false;
        } catch (FileNotFoundException e) {
            LOG.error("OssUtils putObject method is FileNotFoundException", e);
            return false;
        } finally {
            ossClient.shutdown();
        }
        return result.getResponse().isSuccessful();
    }

}
